﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
using FogOutlook.Plugins.Classes;
using Microsoft.Office.Interop.Outlook;
using System.Collections.Generic;
using System.Text;

namespace FogBugz {
	internal partial class FogBugzReport : Form {
		MailItem mi = null;
		FogBugz fb = null;
		internal string result = "";

		private class ComboItem {
			public ComboItem(string text, string id) { this.text = text; this.id = id; }
			public string text;
			public string id;
			public override string ToString() { return text; }
		}

		private class FileListItem {
			public FileListItem(string file, string name) { this.file = file; this.name = name; }
			public readonly string file;
			public readonly string name;
		}

		private ListViewItem lastItem = null;
		private PreviewForm previewForm = new PreviewForm();
		private static string NEW_TITLE = "Enter a title here...";

		public FogBugzReport(FogBugz fb, MailItem mi) {
			InitializeComponent();
			this.mi = mi;
			this.fb = fb;
			title.Text = NEW_TITLE;
			previewColumnHeader.Width = -2;
		}

		private void FogBugzReport_Load(object sender, EventArgs e) {
			LoadData();
			if(mi != null) {
				title.Text = mi.Subject;
				if(mi != null) {
					correspondent.Text = fb.senderAddress;
					report.Text = Regex.Replace(mi.Body, "HYPERLINK \"(mailto:)?(?<url>[^\"]*)\"(?<turl>.*)", "${url} ");
					title.Text = mi.Subject;

					foreach(Attachment att in mi.Attachments) {
						string file = GetTempFilePathWithExtension(Path.GetExtension(att.FileName));
						att.SaveAsFile(file);
						ListViewItem lvi = listFiles.Items.Add(att.DisplayName);
						lvi.Tag = new FileListItem(file, att.FileName);
						lvi.Checked = !Regex.IsMatch(att.FileName, "image[0-9]{3}.(png|jpg)"); // Try to exclude signature images by unchecking them, unfortunately they may be contained images instead :/
					}
					if(listFiles.Items.Count > 0)
						listFiles.Items[0].Selected = true;
				}
			}
		}

		private void LoadData() {
			XmlNodeList list;
			if(fb.data.TryGetValue("assignedTo", out list)) { // Needs to be prior to project since the project selection sets the primary contact
				String xpath = String.Format("person", project.SelectedItem);
				FillData(assignedTo, list.Item(0).SelectNodes(xpath), "sFullName", "ixPerson");
			}
			if(fb.data.TryGetValue("project", out list)) {
				FillData(project, list.Item(0).SelectNodes("project"), "sProject", "ixProject");
			}
			if(fb.data.TryGetValue("category", out list)) {
				String xpath = String.Format("category", project.SelectedItem);
				FillData(category, list.Item(0).SelectNodes(xpath), "sCategory", "ixCategory");
			}
			if(fb.data.TryGetValue("priority", out list)) {
				String xpath = String.Format("priority", project.SelectedItem);
				FillData(priority, list.Item(0).SelectNodes(xpath), "sPriority", "ixPriority");
				XmlNode node = list.Item(0).SelectSingleNode("priority[fDefault='true']/ixPriority");
				if(node != null) {
					foreach(ComboItem ci in priority.Items) {
						if(((ComboItem)ci).id.Equals(node.InnerText)) {
							priority.SelectedItem = ci;
							break;
						}
					}
				}
			}
		}

		private void LoadSubData() {
			area.Items.Clear();
			milestone.Items.Clear();
			XmlNodeList list;
			if(fb.data.TryGetValue("area", out list)) {
				String xpath = String.Format("area[sProject='{0}']", project.SelectedItem);
				FillData(area, list.Item(0).SelectNodes(xpath), "sArea", "ixArea");
			}
			if(fb.data.TryGetValue("milestone", out list)) {
				String xpath = String.Format("fixfor[sProject='{0}']|fixfor[sProject='']", project.SelectedItem);
				FillData(milestone, list.Item(0).SelectNodes(xpath), "sFixFor", "ixFixFor");
			}
		}

		private void FillData(ComboBox cb, XmlNodeList list, String sName, String ixName) {
			foreach(XmlNode node in list)
				cb.Items.Add(new ComboItem(node.SelectSingleNode(sName).InnerText, node.SelectSingleNode(ixName).InnerText));
			if(cb.Items.Count > 0)
				cb.SelectedIndex = 0;
		}

		private void DrawRoundRect(Graphics g, Pen p, float X, float Y, float width, float height, float radius) {
			GraphicsPath gp = new GraphicsPath();
			gp.AddLine(X + radius, Y, X + width - (radius * 2), Y);
			gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90);
			gp.AddLine(X + width, Y + radius, X + width, Y + height - (radius * 2));
			gp.AddArc(X + width - (radius * 2), Y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
			gp.AddLine(X + width - (radius * 2), Y + height, X + radius, Y + height);
			gp.AddArc(X, Y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
			gp.AddLine(X, Y + height - (radius * 2), X, Y + radius);
			gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90);
			gp.CloseFigure();
			g.DrawPath(p, gp);
			gp.Dispose();
		}

		private void casePanel_Paint(object sender, PaintEventArgs e) {
			Graphics v = e.Graphics;
			v.ResetClip();
			DrawRoundRect(v, Pens.Black, e.ClipRectangle.Left, e.ClipRectangle.Top, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1, 10);
			//Without rounded corners
			//e.Graphics.DrawRectangle(Pens.Blue, e.ClipRectangle.Left, e.ClipRectangle.Top, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1);
			base.OnPaint(e);
		}

		private void title_TextChanged(object sender, EventArgs e) {
			if(title.Text.Equals(NEW_TITLE))
				title.ForeColor = SystemColors.ControlDark;
			else
				title.ForeColor = SystemColors.WindowText;
		}

		private void title_Click(object sender, EventArgs e) {
			title.SelectAll();
		}

		private void project_SelectedIndexChanged(object sender, EventArgs e) {
			XmlNodeList list;
			if(fb.data.TryGetValue("project", out list)) {
				LoadSubData();
				XmlNode node = list.Item(0).SelectSingleNode(String.Format("project[sProject='{0}']/sPersonOwner", project.Text));
				if(node != null)
					assignedTo.Text = node.InnerText;
			}
		}

		public string GetTempFilePathWithExtension(string extension) {
			var path = Path.GetTempPath();
			var fileName = Guid.NewGuid().ToString() + extension;
			return Path.Combine(path, fileName);
		}

		private void listFiles_MouseMove(object sender, MouseEventArgs e) {
			Point ptCursor = Cursor.Position;
			ptCursor = listFiles.PointToClient(ptCursor);
			ListViewItem Item = listFiles.GetItemAt(ptCursor.X, ptCursor.Y);
			if(Item != null && Item == lastItem) {
				Point loc = Cursor.Position;
				loc.Y -= previewForm.Height + 5;
				loc.X += 5;
				previewForm.Location = loc;
			}
			else {
				if(Item != null) {
					FileListItem fli = Item.Tag as FileListItem;
					string ext = Path.GetExtension(fli.file);
					if(ext.Equals(".jpg", StringComparison.InvariantCultureIgnoreCase) || ext.Equals(".png", StringComparison.InvariantCultureIgnoreCase) ||
					ext.Equals(".gif", StringComparison.InvariantCultureIgnoreCase) || ext.Equals(".bmp", StringComparison.InvariantCultureIgnoreCase)) {
						previewForm.attachPreview.Load(fli.file);
						if(previewForm.attachPreview.Image.Width > 220 || previewForm.attachPreview.Image.Height > 160) {
							previewForm.attachPreview.SizeMode = PictureBoxSizeMode.StretchImage;
							previewForm.ClientSize = new System.Drawing.Size(220, 160);
						}
						else {
							previewForm.attachPreview.SizeMode = PictureBoxSizeMode.Normal;
							previewForm.ClientSize = new System.Drawing.Size(previewForm.attachPreview.Image.Width, previewForm.attachPreview.Image.Height);
						}
						Point loc = Cursor.Position;
						loc.Y -= previewForm.attachPreview.Height + 5;
						loc.X += 5;
						previewForm.Location = loc;
						previewForm.Show();
						lastItem = Item;
						return;
					}
				}
				lastItem = null;
				previewForm.attachPreview.Image = null;
				previewForm.Hide();
			}
		}

		private void listFiles_MouseLeave(object sender, EventArgs e) {
			lastItem = null;
			previewForm.attachPreview.Image = null;
			previewForm.Hide();
		}

		private void btnSubmit_Click(object sender, EventArgs e) {
		/*	string[] files = new string[listFiles.CheckedItems.Count];
			int i=0;
			foreach(ListViewItem lvi in listFiles.CheckedItems)
				files[i++] = lvi.Tag.ToString();
			*/
			Dictionary<string, string> args = new Dictionary<string, string>();
			if(title.Text.Length > 0)
				args.Add("sTitle", title.Text);
			args.Add("ixProject", ((ComboItem)project.SelectedItem).id);
			args.Add("ixCategory", ((ComboItem)category.SelectedItem).id);
			args.Add("ixPersonAssignedTo", ((ComboItem)assignedTo.SelectedItem).id);
			args.Add("ixPriority", ((ComboItem)priority.SelectedItem).id);
			args.Add("ixArea", ((ComboItem)area.SelectedItem).id);
			args.Add("ixFixFor", ((ComboItem)milestone.SelectedItem).id);
			if(parentCase.Text.Length > 0)
				args.Add("ixBugParent", parentCase.Text);

			if(report.Text.Length > 0)
				args.Add("sEvent", report.Text);

			ASCIIEncoding encoding = new ASCIIEncoding();
			Dictionary<string, byte[]>[] rgFiles = null;
			if(listFiles.CheckedItems.Count > 0) {
				rgFiles = new Dictionary<string, byte[]>[listFiles.CheckedItems.Count];
				int i = 0;
				foreach(ListViewItem lvi in listFiles.CheckedItems) {
					FileListItem fli = lvi.Tag as FileListItem;
					rgFiles[i] = new Dictionary<string, byte[]>();
					rgFiles[i]["name"] = encoding.GetBytes("File" + (i + 1).ToString());
					rgFiles[i]["filename"] = encoding.GetBytes(fli.name);
					rgFiles[i]["contenttype"] = encoding.GetBytes(fb.GetMIMEType(fli.file));
					FileStream fs = new FileStream(fli.file, FileMode.Open);
					BinaryReader br = new BinaryReader(fs);
					rgFiles[i]["data"] = br.ReadBytes((int)fs.Length);
/*					rgFiles[i]["filename"] = encoding.GetBytes(Path.GetFileName(filename));
					rgFiles[i]["contenttype"] = encoding.GetBytes(fb.GetMIMEType(filename));
					FileStream fs = new FileStream(filename, FileMode.Open);
					BinaryReader br = new BinaryReader(fs);
					rgFiles[i]["data"] = br.ReadBytes((int)fs.Length);*/
					fs.Close();
					++i;
				}
				args.Add("nFileCount", listFiles.CheckedItems.Count.ToString());
			}

			if(correspondent.Text.Length > 0)
				args.Add("sCustomerEmail", correspondent.Text);
			result = fb.api.Cmd("new", args, rgFiles);
			DialogResult = System.Windows.Forms.DialogResult.OK;
			Close(); // parent dispose of us
		}
	}
}